package org.etom.impl.connector.datatypes;

import java.io.File;
import java.io.InputStream;
import java.net.HttpURLConnection;
import java.net.URL;
import java.util.Iterator;
import java.util.Map;

import org.etom.connector.datatypes.IMoodleCourse;
import org.etom.connector.datatypes.IMoodleModule;
import org.etom.connector.service.ConnectorException;
import org.etom.impl.connector.util.Uploader;
import org.etom.impl.connector.util.XmlRpcClientWrapper;

/**
 * Implementation of the Moodle module.
 * The instances of that class are particularly mutable. 
 */
public class MoodleModuleImpl implements IMoodleModule {

  private static final String ASSIGMENT_ID_KEY_SINGLE = "?a=";//it is a moodle specific constant
  private static final String ASSIGMENT_ID_KEY_MULTI  = "&a=";//it is a moodle specific constant
  
  private boolean areRequestPropsSet;
  private boolean isCourseSet;
  private boolean isTypeSet;
  private Long id;
  private String name;
  private String referenceName;
  private String description;
  private int type;
//  private String moduleURL;
  private XmlRpcClientWrapper xmlRpcClientWrapper;
  private String rpcLibUrl;
  private IMoodleCourse course;
  private Map<String, String> requestProps;
  
  /**
   * Construct a new Moodle module.
   * 
   * @param id - the identifier of the module, as is received from the server
   * @param name - the module name
   * @param referenceName - the module reference name, in case of resource represents the file name
   * @param xmlRpcClientWrapper - xml rpc wrapper
   */
  public MoodleModuleImpl(Long id, String name, String referenceName,
      String description, XmlRpcClientWrapper xmlRpcClientWrapper) {
    this.id = id;
    this.name = name;
    this.referenceName = referenceName;
    this.description = description;
    this.xmlRpcClientWrapper = xmlRpcClientWrapper;
    areRequestPropsSet = false;
    isCourseSet = false;
    isTypeSet = false;
    init();
  }
  
  /**
   * The method sets the request properties. They are used in connections to the server.
   * 
   * @param requestProps - the request properties
   */
  public void setRequestProperties(Map<String, String> requestProps) {
    this.requestProps = requestProps;
    areRequestPropsSet = true;
  }
  
  /**
   * The method sets the course.
   * 
   * @param course - the course which the module is part of
   */
  public void setCourse(IMoodleCourse course) {
    this.course = course;
    isCourseSet = true;
  }
  
  /**
   * @see org.etom.connector.datatypes.IMoodleModule#getId()
   */
  public Long getId() {
    checkState();
    return id;
  }
  
  /**
   * @see org.etom.connector.datatypes.IMoodleModule#getName()
   */
  public String getName() {
    checkState();
    return name;
  }

  /**
   * @see org.etom.connector.datatypes.IMoodleModule#getReferenceName()
   */
  public String getReferenceName() {
    checkState();
    return referenceName;
  }
  
  /**
   * @see org.etom.connector.datatypes.IMoodleModule#getDescription()
   */
  public String getDescription() {
    checkState();
    return description;
  }

  /**
   * @see org.etom.connector.datatypes.IMoodleModule#getType()
   */
  public int getType() {
    checkState();
    return type;
  }
  
  /**
   * The method sets the module type.
   * 
   * @param type - the module type
   */
  public void setType(int type) {
    this.type = type;
    isTypeSet = true;
  }
  
  /**
   * @see org.etom.connector.datatypes.IMoodleModule#getContent()
   */
  @Override
  public InputStream getContent() throws ConnectorException {
    checkState();
//    if (moduleURL == null)
//      moduleURL = xmlRpcClientWrapper.getMoodleModuleURL(course, this, requestProps);
    String moduleURL = xmlRpcClientWrapper.getMoodleModuleURL(course, this, requestProps);
    try {
      URL moduleContentUrl = new URL(moduleURL);
      HttpURLConnection connection = (HttpURLConnection) moduleContentUrl.openConnection();
      Iterator<String> keysIter = requestProps.keySet().iterator();
      String currentKey;
      while (keysIter.hasNext()) {
        currentKey = keysIter.next();
        connection.setRequestProperty(currentKey, requestProps.get(currentKey));
      }
      connection.setDoOutput(true);
      connection.setUseCaches(false);
      return connection.getInputStream();
    } catch (Exception e) {
      throw new ConnectorException("The content is not accessible! Module: " + getName(),
          ConnectorException.CONNECTION_ERROR, e);
    }
  }

  /**
   * @see org.etom.connector.datatypes.IMoodleModule#setContent(java.io.File)
   */
  @Override
  public void setContent(File contentFile) throws ConnectorException {
    checkState();
    Uploader.upload(rpcLibUrl, contentFile, requestProps);
  }
  
  /**
   * @see org.etom.connector.datatypes.IMoodleModule#getCourse()
   */
  @Override
  public IMoodleCourse getCourse() {
    checkState();
    return course;
  }

  private void checkState() {
    if (!areRequestPropsSet)
      throw new IllegalStateException(
          "The mandatory properties of the moodle module are not set!");
    if (!isCourseSet)
      throw new IllegalStateException(
          "The mandatory course of the moodle module is not set!");
    if (!isTypeSet)
      throw new IllegalStateException(
          "The mandatory type of the moodle module is not set!");
  }
  
  /*
   * An utility method which initializes the module.
   */
  private void init() {
    rpcLibUrl = xmlRpcClientWrapper.getRpcLibUrl();
    if (rpcLibUrl.indexOf('?') == -1) {
      rpcLibUrl += ASSIGMENT_ID_KEY_SINGLE;
    } else {
      rpcLibUrl += ASSIGMENT_ID_KEY_MULTI;
    }
    rpcLibUrl += id;
  }
  
  @Override
  public boolean equals(Object other) {
    if (!(other instanceof IMoodleModule)) {
      return false;
    }
    IMoodleModule otherModule = (IMoodleModule) other;
    return this.id.equals(otherModule.getId());
  }

  @Override
  public int hashCode() {
    return this.id.hashCode();
  }
  
}
